Glass Effect Transition
This document provides a comprehensive explanation of Glass Effect Transitions in Scripting, including how Liquid Glass materials animate during view changes, how geometry matching works, and how to correctly use NamespaceReader to access SwiftUI’s @Namespace within TSX code.
Contents include:
- Overview of Liquid Glass transitions
- The three transition types
- Relationship among
glassEffectTransition, glassEffectID, and namespace
- Role of
glassEffectUnion
- Purpose and behavior of
GlassEffectContainer
- Design and usage of
NamespaceReader
- Detailed walkthrough of the provided example
- Best practice recommendations
1. Overview: What Is a Glass Effect Transition?
A Glass Effect Transition defines how a Liquid Glass material animates when:
- A view is inserted or removed
- Layout changes
- Views switch between two states
1type GlassEffectTransition = 'identity' | 'materialize' | 'matchedGeometry'
These transitions affect only the Liquid Glass material—not the rest of the view’s opacity or scale.
A transition controls:
- How the glass material appears or disappears
- Whether the shape of the glass participates in animation
- Whether the glass attempts to match geometry with other shapes
2. Transition Types
2.1 identity
1glassEffectTransition="identity"
Behavior:
- No animation or geometry change.
- The glass effect appears immediately with no fade or shape transformation.
Use cases:
- Disabling animations
- Static UI
- Debugging transitions
2.2 materialize
1glassEffectTransition="materialize"
Behavior:
- The material fades in or out smoothly.
- No attempt is made to match geometry with any other glass shape.
- Content transitions in a simple, clean way.
Use cases:
- Basic menu transitions
- Buttons appearing or disappearing
- When geometric continuity is not needed
2.3 matchedGeometry (most powerful)
1glassEffectTransition="matchedGeometry"
Behavior:
- The Liquid Glass shape morphs between views that share the same ID and namespace.
- Creates smooth, fluid transitions between corresponding glass shapes.
- Requires
glassEffectID and namespace.
Use cases:
- Menu switching (e.g., Edit → Home)
- Toolbar reconfiguration
- Any UI element where continuity matters
3. glassEffectID and namespace
The core of geometric matching
Liquid Glass’ geometric-matching transitions require the ability to identify and relate specific glass shapes.
3.1 Why IDs Are Required
To animate a shape from state A → state B, the system must know:
- which old shape matches which new shape
The identity is provided by:
1glassEffectID={{
2 id: 1,
3 namespace
4}}
Views with the same id in the same namespace are treated as the same conceptual glass entity across states.
3.2 Why a namespace Is Required
SwiftUI’s matchedGeometry system requires an @Namespace to define the animation scope.
Since TSX cannot define SwiftUI property wrappers, Scripting provides:
1<NamespaceReader>
2 {namespace => (…)}
3</NamespaceReader>
Inside the closure:
namespace refers to a real SwiftUI @Namespace
- All
glassEffectID and glassEffectUnion inside this closure must use this namespace
Benefits:
- Provides correct scope for geometry transitions
- Prevents accidental cross-scope animation
- Ensures matchedGeometry and unions behave predictably
Without a namespace, geometric matching does not work.
4. glassEffectUnion: Unifying Glass Regions
glassEffectUnion merges multiple views into a single continuous glass material region.
1glassEffectUnion={{
2 id: 1,
3 namespace
4}}
Effects:
- Buttons appear to share a single underlying piece of glass
- Material may shift or reflow cohesively
- Enhances visual coherence in grouped UI elements
Typically paired with matchedGeometry transitions.
5. GlassEffectContainer
The container provides:
- A shared environment for geometry matching
- A rendering boundary for unioned glass
- Optimized rendering for clusters of Liquid Glass views
Example:
1<GlassEffectContainer>
2 <HStack> ... </HStack>
3</GlassEffectContainer>
Every view participating in glass transitions should be placed inside the same container.
6. NamespaceReader
Exposing SwiftUI’s @Namespace to TSX
6.1 Why NamespaceReader Exists
SwiftUI defines matchedGeometry transitions using:
1@Namespace private var namespace
But TSX code cannot create Swift @Namespace values.
Therefore Scripting provides:
1<NamespaceReader>
2 {namespace => (…)}
3</NamespaceReader>
Purpose:
- Internally creates and manages a real SwiftUI
@Namespace
- Makes the namespace accessible to JavaScript/TypeScript
- Ensures all participating views share the same namespace
- Enables matchedGeometry transitions to work in TSX
6.2 How It Works
- NamespaceReader creates a SwiftUI view containing
@Namespace.
- That namespace is passed to the TSX children via a function parameter.
- All
glassEffectID and glassEffectUnion must use this namespace.
- All participating views inside the closure are guaranteed to match within the same namespace.
7. Example Analysis
Below is the provided example, demonstrating a dynamic menu switching between two states:
- Menu A: Home / Settings
- Menu B: Edit / Erase / Delete
- Using animation for transitions
- Using matchedGeometry via ID sharing
- Using union IDs for continuous material appearance
Key excerpts:
1isAlternativeMenu.value
2 ? <>
3 <Button
4 title="Home"
5 glassEffectID={{id:1, namespace}}
6 glassEffectUnion={{id:1,namespace}}
7 />
8 <Button
9 title="Settings"
10 glassEffectID={{id:2, namespace}}
11 glassEffectUnion={{id:1,namespace}}
12 />
13 </>
14 : <>
15 <Button
16 title="Edit"
17 glassEffectID={{id:1, namespace}}
18 glassEffectUnion={{id:1,namespace}}
19 />
20 <Button
21 title="Erase"
22 glassEffectID={{id:3, namespace}}
23 glassEffectUnion={{id:1,namespace}}
24 glassEffectTransition="materialize"
25 />
26 <Button
27 title="Delete"
28 glassEffectID={{id:2, namespace}}
29 glassEffectUnion={{id:1,namespace}}
30 />
31 </>
1. Shared union (id = 1)
All buttons belong to the same glass union.
This produces a smooth, unified underlying glass region.
2. Shared glassEffectID for corresponding buttons
Home and Edit share id = 1
Settings and Delete share id = 2
→ They animate between each other using matchedGeometry.
3. “Erase” uses a different transition
1glassEffectTransition="materialize"
This button fades its material rather than matching geometry, making its appearance more distinct.
4. Animation is triggered explicitly
1withAnimation(() => {
2 isAlternativeMenu.setValue(
3 !isAlternativeMenu.value
4 )
5})
Glass transitions attach themselves to this animation transaction automatically.
8. Best Practices
1. Use a single GlassEffectContainer
All participating glass views must share one container.
2. Use one NamespaceReader per animated region
Do not create multiple namespaces unless intentionally separating animation scopes.
3. Use consistent glassEffectID between states
Both old and new states must contain the same ID to animate geometrically.
4. Use glassEffectUnion for cohesive material appearance
Especially in toolbars and menus.
5. Prefer matchedGeometry for sophisticated transitions
Use materialize only for elements needing simple appearance behavior.
9. Summary
Glass Effect Transitions enable highly expressive and fluid animations for Liquid Glass materials in iOS 26.
In Scripting:
glassEffectTransition defines how the material animates
glassEffectID and namespace enable geometric matching
glassEffectUnion creates unified material regions
GlassEffectContainer manages the animation environment
NamespaceReader exposes SwiftUI’s @Namespace to TSX, making advanced animations possible